home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume9 / ed_ip < prev    next >
Encoding:
Text File  |  1989-11-26  |  40.3 KB  |  1,876 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v09i036: "ed" clone
  4. Reply-To: unknown@unknown.UUCP (Ian Phillipps)
  5.  
  6. Posting-number: Volume 9, Issue 36
  7. Submitted-by: unknown@unknown.UUCP (Ian Phillipps)
  8. Archive-name: ed_ip
  9.  
  10. [Attributions and addresses lost -- please don't send compressed tar files
  11. without prior arrangement!  ++bsa]
  12.  
  13. #! /bin/sh
  14. # This is a shell archive.  Remove anything before this line, then unpack
  15. # it by saving it into a file and typing "sh file".  To overwrite existing
  16. # files, type "sh file -c".  You can also feed this as standard input via
  17. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  18. # will see the following message at the end:
  19. #        "End of shell archive."
  20. # Contents:  ed.c ed.man read.me
  21. # Wrapped by allbery@uunet on Sun Nov 26 15:38:36 1989
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. if test -f 'ed.c' -a "${1}" != "-c" ; then 
  24.   echo shar: Will not clobber existing file \"'ed.c'\"
  25. else
  26. echo shar: Extracting \"'ed.c'\" \(27843 characters\)
  27. sed "s/^X//" >'ed.c' <<'END_OF_FILE'
  28. X/*
  29. X *  ed - standard editor
  30. X *  ~~
  31. X *    Authors: Brian Beattie, Kees Bot, and others
  32. X *
  33. X * Copyright 1987 Brian Beattie Rights Reserved.
  34. X * Permission to copy or distribute granted under the following conditions:
  35. X * 1). No charge may be made other than reasonable charges for reproduction.
  36. X * 2). This notice must remain intact.
  37. X * 3). No further restrictions may be added.
  38. X * 4). Except meaningless ones.
  39. X *
  40. X * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  41. X *  TurboC mods and cleanup 8/17/88 RAMontante.
  42. X *  Further information (posting headers, etc.) at end of file.
  43. X *  RE stuff replaced with Spencerian version, sundry other bugfix+speedups
  44. X *  Ian Phillipps. Version incremented to "5".
  45. X * _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
  46. X */
  47. X
  48. Xint    version = 5;    /* used only in the "set" function, for i.d. */
  49. X
  50. X#include <stdio.h>
  51. X/* Regexp is Henry Spencer's package. WARNING: regsub is modified to return
  52. X * a pointer to the \0 after the destination string, and this program refers
  53. X * to the "private" reganch field in the struct regexp.
  54. X */
  55. X#include <regexp.h>
  56. X
  57. X#ifdef __TURBOC__
  58. X#include <stdlib.h>
  59. X#include <signal.h>
  60. X#include <string.h>
  61. X#include <ctype.h>
  62. X#include <io.h>
  63. X
  64. X#define    _cleanup()    ;
  65. X
  66. X#endif  /* ifdef __TURBOC__  */
  67. X
  68. X
  69. X/*
  70. X *    #defines for non-printing ASCII characters
  71. X */
  72. X#define NUL    0x00    /* ^@ */
  73. X#define EOS    0x00    /* end of string */
  74. X#define SOH    0x01    /* ^A */
  75. X#define STX    0x02    /* ^B */
  76. X#define ETX    0x03    /* ^C */
  77. X#define EOT    0x04    /* ^D */
  78. X#define ENQ    0x05    /* ^E */
  79. X#define ACK    0x06    /* ^F */
  80. X#define BEL    0x07    /* ^G */
  81. X#define BS    0x08    /* ^H */
  82. X#define HT    0x09    /* ^I */
  83. X#define LF    0x0a    /* ^J */
  84. X#define NL    '\n'
  85. X#define VT    0x0b    /* ^K */
  86. X#define FF    0x0c    /* ^L */
  87. X#define CR    0x0d    /* ^M */
  88. X#define SO    0x0e    /* ^N */
  89. X#define SI    0x0f    /* ^O */
  90. X#define DLE    0x10    /* ^P */
  91. X#define DC1    0x11    /* ^Q */
  92. X#define DC2    0x12    /* ^R */
  93. X#define DC3    0x13    /* ^S */
  94. X#define DC4    0x14    /* ^T */
  95. X#define NAK    0x15    /* ^U */
  96. X#define SYN    0x16    /* ^V */
  97. X#define ETB    0x17    /* ^W */
  98. X#define CAN    0x18    /* ^X */
  99. X#define EM    0x19    /* ^Y */
  100. X#define SUB    0x1a    /* ^Z */
  101. X#define ESC    0x1b    /* ^[ */
  102. X#define FS    0x1c    /* ^\ */
  103. X#define GS    0x1d    /* ^] */
  104. X#define RS    0x1e    /* ^^ */
  105. X#define US    0x1f    /* ^_ */
  106. X#define SP    0x20    /* space */
  107. X#define DEL    0x7f    /* DEL*/
  108. X#define ESCAPE  '\\'
  109. X
  110. X
  111. X#define TRUE    1
  112. X#define FALSE    0
  113. X#define ERR        -2
  114. X#define FATAL        (ERR-1)
  115. X#define CHANGED        (ERR-2)
  116. X#define SET_FAIL    (ERR-3)
  117. X#define SUB_FAIL    (ERR-4)
  118. X#define MEM_FAIL    (ERR-5)
  119. X
  120. X
  121. X#define    BUFFER_SIZE    2048    /* stream-buffer size:  == 1 hd cluster */
  122. X
  123. X#define LINFREE    1    /* entry not in use */
  124. X#define LGLOB    2       /* line marked global */
  125. X
  126. X#define MAXLINE    512    /* max number of chars per line */
  127. X#define MAXPAT    256    /* max number of chars per replacement pattern */
  128. X#define MAXFNAME 256    /* max file name size */
  129. X
  130. X
  131. X/**  Global variables  **/
  132. X
  133. Xstruct    line {
  134. X    int        l_stat;        /* empty, mark */
  135. X    struct line    *l_prev;
  136. X    struct line    *l_next;
  137. X    char        l_buff[1];
  138. X};
  139. Xtypedef struct line    LINE;
  140. X
  141. X
  142. Xint    diag = 1;        /* diagnostic-output? flag */
  143. Xint    truncflg = 1;    /* truncate long line flag */
  144. Xint    eightbit = 1;    /* save eighth bit */
  145. Xint    nonascii;    /* count of non-ascii chars read */
  146. Xint    nullchar;    /* count of null chars read */
  147. Xint    truncated;    /* count of lines truncated */
  148. Xchar    fname[MAXFNAME];
  149. Xint    fchanged;    /* file-changed? flag */
  150. Xint    nofname;
  151. Xint    mark['z'-'a'+1];
  152. Xregexp    *oldpat;
  153. X
  154. XLINE    Line0;
  155. Xint    CurLn = 0;
  156. XLINE    *CurPtr = &Line0;    /* CurLn and CurPtr must be kept in step */
  157. Xint    LastLn = 0;
  158. Xchar    inlin[MAXLINE];
  159. Xint    pflag;
  160. Xint    Line1, Line2, nlines;
  161. Xint    nflg;        /* print line number flag */
  162. Xint    lflg;        /* print line in verbose mode */
  163. Xint    pflg;        /* print current line after each command */
  164. Xchar    *inptr;        /* tty input buffer */
  165. X
  166. Xstruct tbl {
  167. X    char    *t_str;
  168. X    int    *t_ptr;
  169. X    int    t_val;
  170. X} *t, tbl[] = {
  171. X    "number",    &nflg,        TRUE,
  172. X    "nonumber",    &nflg,        FALSE,
  173. X    "list",        &lflg,        TRUE,
  174. X    "nolist",    &lflg,        FALSE,
  175. X    "eightbit",    &eightbit,    TRUE,
  176. X    "noeightbit",    &eightbit,    FALSE,
  177. X    0
  178. X};
  179. X
  180. X
  181. X/*-------------------------------------------------------------------------*/
  182. X
  183. X#ifdef __TURBOC__        /*  prototypes (unneeded?)  */
  184. X
  185. Xvoid    prntln(char *, int, int);
  186. Xvoid    putcntl(char , FILE *);
  187. Xint    doprnt(int, int);
  188. XLINE    *getptr(int);
  189. Xint    del(int, int);
  190. Xint    ins(char *);
  191. Xint    append(int, int);
  192. Xint    deflt(int, int);
  193. Xregexp    *optpat(void);
  194. Xint    egets( char*, int, FILE* );
  195. Xint    ckglob( void );
  196. Xint    doglob( void );
  197. Xint    docmd( int );
  198. Xint    dolst( int, int );
  199. Xint    doread( int, char* );
  200. Xint    dowrite( int, int, char*, int );
  201. Xint    find( regexp*, int );
  202. Xchar*    getfn( void );
  203. Xint    getlst( void );
  204. Xint    getnum( int );
  205. Xint    getone( void );
  206. Xint    getrhs( char* );
  207. Xint    join( int, int );
  208. Xint    move( int );
  209. Xint    set( void );
  210. Xint    subst( regexp*, char*, int, int );
  211. Xint    transfer( int );
  212. X
  213. X#else    /* !__TURBOC__ */
  214. X
  215. Xextern    char    *strcpy();
  216. Xextern    int    *malloc();
  217. Xextern    LINE    *getptr();
  218. Xextern    char    *gettxt();
  219. Xextern    char    *gettxtl();
  220. Xextern    char    *catsub();
  221. Xregexp    *optpat();
  222. X
  223. X#endif  /* __TURBOC__ */
  224. X
  225. X
  226. X/*________  Macros  ________________________________________________________*/
  227. X
  228. X#ifndef max
  229. X#  define max(a,b)    ((a) > (b) ? (a) : (b))
  230. X#endif
  231. X
  232. X#ifndef min
  233. X#  define min(a,b)    ((a) < (b) ? (a) : (b))
  234. X#endif
  235. X
  236. X#ifndef toupper
  237. X#  define toupper(c)    ((c >= 'a' && c <= 'z') ? c-32 : c )
  238. X#endif
  239. X
  240. X#define nextln(l)    ((l)+1 > LastLn ? 0 : (l)+1)
  241. X#define prevln(l)    ((l)-1 < 0 ? LastLn : (l)-1)
  242. X
  243. X#define gettxtl(lin)    ((lin)->l_buff)
  244. X#define gettxt(num)    (gettxtl( getptr(num) ))
  245. X
  246. X#define getnextptr(p)    ((p)->l_next)
  247. X#define getprevptr(p)    ((p)->l_prev)
  248. X
  249. X#define setCurLn( lin )    ( CurPtr = getptr( CurLn = (lin) ) )
  250. X#define nextCurLn()    ( CurLn = nextln(CurLn), CurPtr = getnextptr( CurPtr ) )
  251. X#define prevCurLn()    ( CurLn = prevln(CurLn), CurPtr = getprevptr( CurPtr ) )
  252. X
  253. X#define clrbuf()    del(1, LastLn)
  254. X
  255. X#define    Skip_White_Space    {while (*inptr==SP || *inptr==HT) inptr++;}
  256. X
  257. X#define relink(a, x, y, b) { (x)->l_prev = (a); (y)->l_next = (b); }
  258. X
  259. X
  260. X/*________  functions  ______________________________________________________*/
  261. X
  262. X
  263. X/*    append.c    */
  264. X
  265. Xappend(line, glob)
  266. Xint    line, glob;
  267. X{
  268. X    char    lin[MAXLINE];
  269. X
  270. X    if(glob)
  271. X        return(ERR);
  272. X    setCurLn( line );
  273. X    for (;;) {
  274. X        char *p = lin;
  275. X        if(nflg)
  276. X            printf("%6d. ",CurLn+1);
  277. X        while( p < &lin[ MAXLINE ] ) {
  278. X            int ch = getchar();
  279. X            if( ch == EOF )
  280. X                return EOF;
  281. X            if( ch == '\n' ) {
  282. X                *p = EOS; break;
  283. X            }
  284. X            *p++ = ch;
  285. X        }
  286. X        if(lin[0] == '.' && lin[1] == '\0')
  287. X            return(0);
  288. X        if( ins(lin) < 0)
  289. X            return( MEM_FAIL );
  290. X    }
  291. X}
  292. X
  293. X/*    ckglob.c    */
  294. X
  295. Xckglob()
  296. X{
  297. X    regexp    *glbpat;
  298. X    char    c, delim, *lin;
  299. X    int    num;
  300. X    LINE    *ptr;
  301. X
  302. X    c = *inptr;
  303. X
  304. X    if(c != 'g' && c != 'v')
  305. X        return(0);
  306. X    if (deflt(1, LastLn) < 0)
  307. X        return(ERR);
  308. X
  309. X    delim = *++inptr;
  310. X    if(delim <= ' ')
  311. X        return(ERR);
  312. X
  313. X    glbpat = optpat();
  314. X    if(*inptr == delim)
  315. X        inptr++;
  316. X    ptr = getptr(1);
  317. X    for (num=1; num<=LastLn; num++) {
  318. X        ptr->l_stat &= ~LGLOB;
  319. X        if (Line1 <= num && num <= Line2) {
  320. X            lin = gettxtl(ptr);
  321. X            if(regexec(glbpat, lin )) {
  322. X                if (c=='g') ptr->l_stat |= LGLOB;
  323. X            } else {
  324. X                if (c=='v') ptr->l_stat |= LGLOB;
  325. X            }
  326. X        ptr = getnextptr(ptr);
  327. X        }
  328. X    }
  329. X    return(1);
  330. X}
  331. X
  332. X
  333. X/*  deflt.c
  334. X *    Set Line1 & Line2 (the command-range delimiters) if the file is
  335. X *    empty; Test whether they have valid values.
  336. X */
  337. X
  338. Xint deflt(def1, def2)
  339. Xint    def1, def2;
  340. X{
  341. X    if(nlines == 0) {
  342. X        Line1 = def1;
  343. X        Line2 = def2;
  344. X    }
  345. X    return ( (Line1>Line2 || Line1<=0) ? ERR : 0 );
  346. X}
  347. X
  348. X
  349. X/*    del.c    */
  350. X
  351. X/* One of the calls to this function tests its return value for an error
  352. X * condition.  But del doesn't return any error value, and it isn't obvious
  353. X * to me what errors might be detectable/reportable.  To silence a warning
  354. X * message, I've added a constant return statement. -- RAM
  355. X * ... It could check to<=LastLn ... igp
  356. X */
  357. X
  358. Xdel(from, to)
  359. Xint    from, to;
  360. X{
  361. X    LINE    *first, *last, *next, *tmp;
  362. X
  363. X    if(from < 1)
  364. X        from = 1;
  365. X    first = getprevptr( getptr( from ) );
  366. X    last = getnextptr( getptr( to ) );
  367. X    next = first->l_next;
  368. X    while(next != last && next != &Line0) {
  369. X        tmp = next->l_next;
  370. X        free(next);
  371. X        next = tmp;
  372. X    }
  373. X    relink(first, last, first, last);
  374. X    LastLn -= (to - from)+1;
  375. X    setCurLn( prevln(from) );
  376. X    return(0);
  377. X}
  378. X
  379. X
  380. Xint dolst(line1, line2)
  381. Xint line1, line2;
  382. X{
  383. X    int oldlflg=lflg, p;
  384. X
  385. X    lflg = 1;
  386. X    p = doprnt(line1, line2);
  387. X    lflg = oldlflg;
  388. X    return p;
  389. X}
  390. X
  391. X
  392. X/*    esc.c
  393. X * Map escape sequences into their equivalent symbols.  Returns the
  394. X * correct ASCII character.  If no escape prefix is present then s
  395. X * is untouched and *s is returned, otherwise **s is advanced to point
  396. X * at the escaped character and the translated character is returned.
  397. X */
  398. Xesc(s)
  399. Xchar    **s;
  400. X{
  401. X    register int    rval;
  402. X
  403. X    if (**s != ESCAPE) {
  404. X        rval = **s;
  405. X    } else {
  406. X        (*s)++;
  407. X        switch(toupper(**s)) {
  408. X        case '\000':
  409. X            rval = ESCAPE;    break;
  410. X        case 'S':
  411. X            rval = ' ';    break;
  412. X        case 'N':
  413. X            rval = '\n';    break;
  414. X        case 'T':
  415. X            rval = '\t';    break;
  416. X        case 'B':
  417. X            rval = '\b';    break;
  418. X        case 'R':
  419. X            rval = '\r';    break;
  420. X        default:
  421. X            rval = **s;    break;
  422. X        }
  423. X    }
  424. X    return (rval);
  425. X}
  426. X
  427. X
  428. X/*    doprnt.c    */
  429. X
  430. Xint doprnt(from, to)
  431. Xint    from, to;
  432. X{
  433. X    from = (from < 1) ? 1 : from;
  434. X    to = (to > LastLn) ? LastLn : to;
  435. X
  436. X    if(to != 0) {
  437. X        setCurLn( from );
  438. X        while( CurLn <= to ) {
  439. X            prntln( gettxtl( CurPtr ), lflg, (nflg ? CurLn : 0));
  440. X            if( CurLn == to )
  441. X                break;
  442. X            nextCurLn();
  443. X        }
  444. X    }
  445. X    return(0);
  446. X}
  447. X
  448. X
  449. Xvoid prntln(str, vflg, lin)
  450. Xchar    *str;
  451. Xint    vflg, lin;
  452. X{
  453. X    if(lin)
  454. X        printf("%7d ",lin);
  455. X    while(*str && *str != NL) {
  456. X        if(*str < ' ' || *str >= 0x7f) {
  457. X            switch(*str) {
  458. X            case '\t':
  459. X                if(vflg)
  460. X                    putcntl(*str, stdout);
  461. X                else
  462. X                    putc(*str, stdout);
  463. X                break;
  464. X
  465. X            case DEL:
  466. X                putc('^', stdout);
  467. X                putc('?', stdout);
  468. X                break;
  469. X
  470. X            default:
  471. X                putcntl(*str, stdout);
  472. X                break;
  473. X            }
  474. X        } else
  475. X            putc(*str, stdout);
  476. X        str++;
  477. X    }
  478. X    if(vflg)
  479. X        putchar('$');
  480. X    putchar('\n');
  481. X}
  482. X
  483. X
  484. Xvoid putcntl(c, stream)
  485. Xchar    c;
  486. XFILE    *stream;
  487. X{
  488. X    putc('^', stream);
  489. X    putc((c&31)|'@', stream);
  490. X}
  491. X
  492. X
  493. X/*    egets.c    */
  494. X
  495. Xegets(str,size,stream)
  496. Xchar    *str;
  497. Xint    size;
  498. XFILE    *stream;
  499. X{
  500. X    int    c, count;
  501. X    char    *cp;
  502. X
  503. X    for(count = 0, cp = str; size > count;) {
  504. X        c = getc(stream);
  505. X        if(c == EOF) {
  506. X            *cp = EOS;
  507. X            if(count)
  508. X                puts("[Incomplete last line]");
  509. X            return(count);
  510. X        }
  511. X        else if(c == NL) {
  512. X            *cp = EOS;
  513. X            return(++count);
  514. X        }
  515. X        else if (c == 0)
  516. X            nullchar++;    /* count nulls */
  517. X        else {
  518. X            if(c > 127) {
  519. X                if(!eightbit)        /* if not saving eighth bit */
  520. X                    c = c&127;    /* strip eigth bit */
  521. X                nonascii++;        /* count it */
  522. X            }
  523. X            *cp++ = c;    /* not null, keep it */
  524. X            count++;
  525. X        }
  526. X    }
  527. X    str[count-1] = EOS;
  528. X    if(c != NL) {
  529. X        puts("truncating line");
  530. X        truncated++;
  531. X        while((c = getc(stream)) != EOF)
  532. X            if(c == NL)
  533. X                break;
  534. X    }
  535. X    return(count);
  536. X}  /* egets */
  537. X
  538. X
  539. Xdoread(lin, fname)
  540. Xint    lin;
  541. Xchar    *fname;
  542. X{
  543. X    FILE    *fp;
  544. X    int    err;
  545. X    unsigned long    bytes;
  546. X    unsigned int    lines;
  547. X    static char    str[MAXLINE];
  548. X
  549. X    err = 0;
  550. X    nonascii = nullchar = truncated = 0;
  551. X
  552. X    if (diag) printf("\"%s\" ",fname);
  553. X    if( (fp = fopen(fname, "r")) == NULL ) {
  554. X        puts(" isn't readable.");
  555. X        return( ERR );
  556. X    }
  557. X    setvbuf(fp, NULL, _IOFBF, BUFFER_SIZE);
  558. X    setCurLn( lin );
  559. X    for(lines = 0, bytes = 0;(err = egets(str,MAXLINE,fp)) > 0;) {
  560. X        bytes += err;
  561. X        if(ins(str) < 0) {
  562. X            err = MEM_FAIL;
  563. X            break;
  564. X        }
  565. X        lines++;
  566. X    }
  567. X    fclose(fp);
  568. X    if(err < 0)
  569. X        return(err);
  570. X    if (diag) {
  571. X        printf("%u lines %u bytes",lines,bytes);
  572. X        if(nonascii)
  573. X            printf(" [%d non-ascii]",nonascii);
  574. X        if(nullchar)
  575. X            printf(" [%d nul]",nullchar);
  576. X        if(truncated)
  577. X            printf(" [%d lines truncated]",truncated);
  578. X        putchar('\n');
  579. X    }
  580. X    return( err );
  581. X}  /* doread */
  582. X
  583. X
  584. Xint dowrite(from, to, fname, apflg)
  585. Xint    from, to;
  586. Xchar    *fname;
  587. Xint    apflg;
  588. X{
  589. X    FILE    *fp;
  590. X    int    lin, err;
  591. X    unsigned int    lines;
  592. X    unsigned long    bytes;
  593. X    char    *str;
  594. X    LINE    *lptr;
  595. X
  596. X    err = 0;
  597. X    lines = bytes = 0;
  598. X
  599. X    printf("\"%s\" ",fname);
  600. X    if((fp = fopen(fname,(apflg?"a":"w"))) == NULL) {
  601. X        puts(" can't be opened for writing!");
  602. X        return( ERR );
  603. X    }
  604. X
  605. X    setvbuf(fp, NULL, _IOFBF, BUFFER_SIZE);
  606. X    lptr = getptr(from);
  607. X    for(lin = from; lin <= to; lin++) {
  608. X        str = lptr->l_buff;
  609. X        lines++;
  610. X        bytes += strlen(str) + 1;    /* str + '\n' */
  611. X        if(fputs(str, fp) == EOF) {
  612. X            puts("file write error");
  613. X            err++;
  614. X            break;
  615. X        }
  616. X        fputc('\n', fp);
  617. X        lptr = lptr->l_next;
  618. X    }
  619. X    printf("%u lines %lu bytes\n",lines,bytes);
  620. X    fclose(fp);
  621. X    return( err );
  622. X}  /* dowrite */
  623. X
  624. X
  625. X/*    find.c    */
  626. X
  627. Xfind(pat, dir)
  628. Xregexp    *pat;
  629. Xint    dir;
  630. X{
  631. X    int    i, num;
  632. X    LINE    *lin;
  633. X
  634. X    num = CurLn;
  635. X    lin = CurPtr;
  636. X    for(i=0; i<LastLn; i++ ) {
  637. X        if(regexec( pat, gettxtl( lin ) ))
  638. X            return(num);
  639. X        if( dir )
  640. X            num = nextln(num), lin = getnextptr(lin);
  641. X        else
  642. X            num = prevln(num), lin = getprevptr(lin);
  643. X    }
  644. X    return ( ERR );
  645. X}
  646. X
  647. X
  648. X/*    getfn.c    */
  649. X
  650. Xchar *getfn()
  651. X{
  652. X    static char    file[256];
  653. X    char    *cp;
  654. X
  655. X    if(*inptr == NL) {
  656. X        nofname=TRUE;
  657. X        strcpy(file, fname);
  658. X    } else {
  659. X        nofname=FALSE;
  660. X        Skip_White_Space;
  661. X
  662. X        cp = file;
  663. X        while(*inptr && *inptr != NL && *inptr != SP && *inptr != HT)
  664. X            *cp++ = *inptr++;
  665. X        *cp = '\0';
  666. X
  667. X        if(strlen(file) == 0) {
  668. X            puts("bad file name");
  669. X            return( NULL );
  670. X        }
  671. X    }
  672. X
  673. X    if(strlen(file) == 0) {
  674. X        puts("no file name");
  675. X        return(NULL);
  676. X    }
  677. X    return( file );
  678. X}  /* getfn */
  679. X
  680. X
  681. Xint getnum(first)
  682. Xint first;
  683. X{
  684. X    regexp    *srchpat;
  685. X    int    num;
  686. X    char    c;
  687. X
  688. X    Skip_White_Space;
  689. X
  690. X    if(*inptr >= '0' && *inptr <= '9') {    /* line number */
  691. X        for(num = 0; *inptr >= '0' && *inptr <= '9'; ++inptr) {
  692. X            num = (num * 10) + (*inptr - '0');
  693. X        }
  694. X        return num;
  695. X    }
  696. X
  697. X    switch(c = *inptr) {
  698. X    case '.':
  699. X        inptr++;
  700. X        return (CurLn);
  701. X
  702. X    case '$':
  703. X        inptr++;
  704. X        return (LastLn);
  705. X
  706. X    case '/':
  707. X    case '?':
  708. X        srchpat = optpat();
  709. X        if(*inptr == c)
  710. X            *inptr++;
  711. X        return(find(srchpat,c == '/'?1:0));
  712. X
  713. X    case '-':
  714. X    case '+':
  715. X        return(first ? CurLn : 1);
  716. X
  717. X    case '\'':
  718. X        inptr++;
  719. X        if (*inptr < 'a' || *inptr > 'z')
  720. X            return(EOF);
  721. X        return mark[ *inptr++ - 'a' ];
  722. X
  723. X    default:
  724. X        return ( first ? EOF : 1 );    /* unknown address */
  725. X    }
  726. X}  /* getnum */
  727. X
  728. X
  729. X/*  getone.c
  730. X *    Parse a number (or arithmetic expression) off the command line.
  731. X */
  732. X#define FIRST 1
  733. X#define NOTFIRST 0
  734. X
  735. Xint getone()
  736. X{
  737. X    int    c, i, num;
  738. X
  739. X    if((num = getnum(FIRST)) >= 0) {
  740. X        for (;;) {
  741. X            Skip_White_Space;
  742. X            if(*inptr != '+' && *inptr != '-')
  743. X                break;    /* exit infinite loop */
  744. X
  745. X                        c = *inptr++;
  746. X            if((i = getnum(NOTFIRST)) < 0)
  747. X                return ( i );
  748. X            if(c == '+')
  749. X                num += i;
  750. X            else
  751. X                num -= i;
  752. X        }
  753. X    }
  754. X    return ( num>LastLn ? ERR : num );
  755. X}  /* getone */
  756. X
  757. X
  758. Xgetlst()
  759. X{
  760. X    int    num;
  761. X
  762. X    Line2 = 0;
  763. X    for(nlines = 0; (num = getone()) >= 0;)
  764. X    {
  765. X        Line1 = Line2;
  766. X        Line2 = num;
  767. X        nlines++;
  768. X        if(*inptr != ',' && *inptr != ';')
  769. X            break;
  770. X        if(*inptr == ';')
  771. X            setCurLn( num );
  772. X        inptr++;
  773. X    }
  774. X    nlines = min(nlines, 2);
  775. X    if(nlines == 0)
  776. X        Line2 = CurLn;
  777. X    if(nlines <= 1)
  778. X        Line1 = Line2;
  779. X
  780. X    return ( (num == ERR) ? num : nlines );
  781. X}  /* getlst */
  782. X
  783. X
  784. X/*    getptr.c    */
  785. X
  786. XLINE *getptr(num)
  787. Xint    num;
  788. X{
  789. X    LINE    *ptr;
  790. X    int    j;
  791. X
  792. X    if (2*num>LastLn && num<=LastLn) {    /* high line numbers */
  793. X        ptr = Line0.l_prev;
  794. X        for (j = LastLn; j>num; j--)
  795. X            ptr = ptr->l_prev;
  796. X    } else {                /* low line numbers */
  797. X        ptr = &Line0;
  798. X        for(j = 0; j < num; j++)
  799. X            ptr = ptr->l_next;
  800. X    }
  801. X    return(ptr);
  802. X}
  803. X
  804. X
  805. X/*    getrhs.c    */
  806. X
  807. Xint getrhs(sub)
  808. Xchar    *sub;
  809. X{
  810. X    char delim = *inptr++;
  811. X    char *outmax = sub + MAXPAT;
  812. X    if( delim == NL || *inptr == NL)    /* check for eol */
  813. X        return( ERR );
  814. X    while( *inptr != delim && *inptr != NL ) {
  815. X        if ( sub > outmax )
  816. X            return ERR;
  817. X        if ( *inptr == ESCAPE ) {
  818. X            switch ( *++inptr ) {
  819. X            case 'r':
  820. X                *sub++ = '\r';
  821. X                inptr++;
  822. X                break;
  823. X            case ESCAPE:
  824. X                *sub++ = ESCAPE;
  825. X                *sub++ = ESCAPE;
  826. X                inptr++;
  827. X            case 'n':
  828. X                *sub++ = '\n';
  829. X                inptr++;
  830. X                break;
  831. X            case 'b':
  832. X                *sub++ = '\b';
  833. X                inptr++;
  834. X                break;
  835. X            case '0': {
  836. X                int i=3;
  837. X                *sub = 0;
  838. X                do {
  839. X                    if (*++inptr<'0' || *inptr >'7')
  840. X                        break;
  841. X                    *sub = (*sub<<3) | (*inptr-'0');
  842. X                } while (--i!=0);
  843. X                sub++;
  844. X                } break;
  845. X            default:
  846. X                if ( *inptr != delim )
  847. X                    *sub++ = ESCAPE;
  848. X                *sub++ = *inptr;
  849. X                if ( *inptr != NL )
  850. X                    inptr++;
  851. X            }
  852. X        }
  853. X        else *sub++ = *inptr++;
  854. X    }
  855. X    *sub = '\0';
  856. X
  857. X    inptr++;        /* skip over delimter */
  858. X    Skip_White_Space;
  859. X    if(*inptr == 'g') {
  860. X        *inptr++;
  861. X        return( 1 );
  862. X    }
  863. X    return( 0 );
  864. X}
  865. X
  866. X/*    ins.c    */
  867. X
  868. Xins(str)
  869. Xchar    *str;
  870. X{
  871. X    char    *cp;
  872. X    LINE    *new, *nxt;
  873. X    int    len;
  874. X
  875. X    do {
  876. X        for ( cp = str; *cp && *cp != NL; cp++ )
  877. X            ;
  878. X        len = cp - str;
  879. X        /* cp now points to end of first or only line */
  880. X
  881. X        if((new = (LINE *)malloc(sizeof(LINE)+len)) == NULL)
  882. X            return( MEM_FAIL );     /* no memory */
  883. X
  884. X        new->l_stat=0;
  885. X        strncpy(new->l_buff,str,len);    /* build new line */
  886. X        new->l_buff[len] = EOS;
  887. X        nxt = getnextptr(CurPtr);    /* get next line */
  888. X        relink(CurPtr, new, new, nxt);    /* add to linked list */
  889. X        relink(new, nxt, CurPtr, new);
  890. X        LastLn++;
  891. X        CurLn++;
  892. X        CurPtr = new;
  893. X        str = cp + 1;
  894. X    }
  895. X        while( *cp != EOS );
  896. X    return 1;
  897. X}
  898. X
  899. X
  900. X/*    join.c    */
  901. X
  902. Xint join(first, last)
  903. Xint first, last;
  904. X{
  905. X    char buf[MAXLINE];
  906. X    char *cp=buf, *str;
  907. X    LINE *lin;
  908. X    int num;
  909. X
  910. X    if (first<=0 || first>last || last>LastLn)
  911. X        return(ERR);
  912. X    if (first==last) {
  913. X        setCurLn( first );
  914. X        return 0;
  915. X    }
  916. X    lin = getptr(first);
  917. X    for (num=first; num<=last; num++) {
  918. X        str=gettxtl(lin);
  919. X        while ( *str ) {
  920. X            if (cp >= buf + MAXLINE-1 ) {
  921. X                puts("line too long");
  922. X                return(ERR);
  923. X            }
  924. X            *cp++ = *str++;
  925. X        }
  926. X        lin = getnextptr(lin);
  927. X    }
  928. X    *cp = EOS;
  929. X    del(first, last);
  930. X    if( ins(buf) < 0 )
  931. X        return MEM_FAIL;
  932. X    fchanged = TRUE;
  933. X    return 0;
  934. X}
  935. X
  936. X
  937. X/*  move.c
  938. X *    Unlink the block of lines from Line1 to Line2, and relink them
  939. X *    after line "num".
  940. X */
  941. X
  942. Xint move(num)
  943. Xint    num;
  944. X{
  945. X    int    range;
  946. X    LINE    *before, *first, *last, *after;
  947. X
  948. X    if( Line1 <= num && num <= Line2 )
  949. X        return( ERR );
  950. X    range = Line2 - Line1 + 1;
  951. X    before = getptr(prevln(Line1));
  952. X    first = getptr(Line1);
  953. X    last = getptr(Line2);
  954. X    after = getptr(nextln(Line2));
  955. X
  956. X    relink(before, after, before, after);
  957. X    LastLn -= range;    /* per AST's posted patch 2/2/88 */
  958. X    if (num > Line1)
  959. X        num -= range;
  960. X
  961. X    before = getptr(num);
  962. X    after = getptr(nextln(num));
  963. X    relink(before, first, last, after);
  964. X    relink(last, after, before, first);
  965. X    LastLn += range;    /* per AST's posted patch 2/2/88 */
  966. X    setCurLn( num + range );
  967. X    return( 1 );
  968. X}
  969. X
  970. X
  971. Xint transfer(num)
  972. Xint num;
  973. X{
  974. X    int mid, lin, ntrans;
  975. X
  976. X    if (Line1<=0 || Line1>Line2)
  977. X        return(ERR);
  978. X
  979. X    mid= num<Line2 ? num : Line2;
  980. X
  981. X    setCurLn( num );
  982. X    ntrans=0;
  983. X
  984. X    for (lin=Line1; lin<=mid; lin++) {
  985. X        if( ins(gettxt(lin)) < 0 )
  986. X            return MEM_FAIL;
  987. X        ntrans++;
  988. X    }
  989. X    lin+=ntrans;
  990. X    Line2+=ntrans;
  991. X
  992. X    for ( ; lin <= Line2; lin += 2 ) {
  993. X        if( ins(gettxt(lin)) < 0 )
  994. X            return MEM_FAIL;
  995. X        Line2++;
  996. X    }
  997. X    return(1);
  998. X}
  999. X
  1000. X
  1001. X/*    optpat.c    */
  1002. X
  1003. Xregexp *optpat(void)
  1004. X{
  1005. X    char    delim, str[MAXPAT], *cp;
  1006. X
  1007. X    delim = *inptr++;
  1008. X    cp = str;
  1009. X    while(*inptr != delim && *inptr != NL) {
  1010. X        if(*inptr == ESCAPE && inptr[1] != NL)
  1011. X            *cp++ = *inptr++;
  1012. X        *cp++ = *inptr++;
  1013. X    }
  1014. X
  1015. X    *cp = EOS;
  1016. X    if(*str == EOS)
  1017. X        return(oldpat);
  1018. X    if(oldpat)
  1019. X        free(oldpat);
  1020. X    return oldpat = regcomp(str);
  1021. X}
  1022. X
  1023. X/* regerror.c */
  1024. Xvoid regerror( char *s )
  1025. X{
  1026. X    fprintf( stderr, "ed: %s\n", s );
  1027. X}
  1028. X
  1029. X
  1030. Xset()
  1031. X{
  1032. X    char    word[16];
  1033. X    int    i;
  1034. X
  1035. X    if(*(++inptr) != 't') {
  1036. X        if(*inptr != SP && *inptr != HT && *inptr != NL)
  1037. X            return(ERR);
  1038. X    } else
  1039. X        inptr++;
  1040. X
  1041. X    if ( (*inptr == NL)
  1042. X#ifdef __TURBOC__
  1043. X        || (*inptr == CR)
  1044. X#endif
  1045. X       )
  1046. X    {
  1047. X        printf("ed version %d.%d\n", version/100, version%100);
  1048. X        printf(    "number %s, list %s\n",
  1049. X            nflg?"ON":"OFF",
  1050. X            lflg?"ON":"OFF");
  1051. X        return(0);
  1052. X    }
  1053. X
  1054. X    Skip_White_Space;
  1055. X    for(i = 0; *inptr != SP && *inptr != HT && *inptr != NL;)
  1056. X        word[i++] = *inptr++;
  1057. X    word[i] = EOS;
  1058. X    for(t = tbl; t->t_str; t++) {
  1059. X        if(strcmp(word,t->t_str) == 0) {
  1060. X            *t->t_ptr = t->t_val;
  1061. X            return(0);
  1062. X        }
  1063. X    }
  1064. X    return SET_FAIL;
  1065. X}
  1066. X
  1067. X#ifndef relink
  1068. Xvoid relink(a, x, y, b)
  1069. XLINE    *a, *x, *y, *b;
  1070. X{
  1071. X    x->l_prev = a;
  1072. X    y->l_next = b;
  1073. X}
  1074. X#endif
  1075. X
  1076. X
  1077. Xvoid set_ed_buf(void)
  1078. X{
  1079. X    relink(&Line0, &Line0, &Line0, &Line0);
  1080. X    CurLn = LastLn = 0;
  1081. X    CurPtr = &Line0;
  1082. X}
  1083. X
  1084. X
  1085. X/*    subst.c    */
  1086. X
  1087. Xint subst(pat, sub, gflg, pflag)
  1088. Xregexp    *pat;
  1089. Xchar    *sub;
  1090. Xint    gflg, pflag;
  1091. X{
  1092. X    int    nchngd = 0;
  1093. X    char    *txtptr;
  1094. X    char    *new, buf[MAXLINE];
  1095. X    int    still_running = 1;
  1096. X    LINE    *lastline = getptr( Line2 );
  1097. X
  1098. X    if(Line1 <= 0)
  1099. X        return( SUB_FAIL );
  1100. X    nchngd = 0;        /* reset count of lines changed */
  1101. X
  1102. X    for( setCurLn( prevln( Line1 ) ); still_running; ) {
  1103. X        nextCurLn();
  1104. X        new = buf;
  1105. X        if ( CurPtr == lastline )
  1106. X            still_running = 0;
  1107. X        if ( regexec( pat, txtptr = gettxtl( CurPtr ) ) ) {
  1108. X            do
  1109. X                {
  1110. X                /* Copy leading text */
  1111. X                int diff = pat->startp[0] - txtptr;
  1112. X                strncpy( new, txtptr, diff );
  1113. X                new += diff;
  1114. X                /* Do substitution */
  1115. X                new = regsub( pat, sub, new );
  1116. X                txtptr = pat->endp[0];
  1117. X                }
  1118. X            while( gflg && !pat->reganch && regexec( pat, txtptr ));
  1119. X
  1120. X            /* Copy trailing chars */
  1121. X            while( *txtptr ) *new++ = *txtptr++;
  1122. X
  1123. X            if(new >= buf+MAXLINE)
  1124. X                return( SUB_FAIL );
  1125. X            *new++ = EOS;
  1126. X            del(CurLn,CurLn);
  1127. X            if( ins(buf) < 0 )
  1128. X                return MEM_FAIL;
  1129. X            nchngd++;
  1130. X            if(pflag)
  1131. X                doprnt(CurLn, CurLn);
  1132. X        }
  1133. X        }
  1134. X    return (( nchngd == 0 && !gflg ) ? SUB_FAIL : nchngd);
  1135. X}
  1136. X
  1137. X
  1138. X/*    system.c    */
  1139. X#ifndef __TURBOC__
  1140. X
  1141. X#define SHELL    "/bin/sh"
  1142. X
  1143. Xsystem(c)
  1144. Xchar *c; {
  1145. X    int pid, status;
  1146. X
  1147. X    switch (pid = fork()) {
  1148. X    case -1:
  1149. X        return -1;
  1150. X    case 0:
  1151. X        execl(SHELL, "sh", "-c", c, (char *) 0);
  1152. X        exit(-1);
  1153. X    default:
  1154. X        while (wait(&status) != pid)
  1155. X            ;
  1156. X    }
  1157. X    return status;
  1158. X}
  1159. X#endif  /* ifndef __TURBOC__ */
  1160. X
  1161. X
  1162. X/*  docmd.c
  1163. X *    Perform the command specified in the input buffer, as pointed to
  1164. X *    by inptr.  Actually, this finds the command letter first.
  1165. X */
  1166. X
  1167. Xint docmd(glob)
  1168. Xint    glob;
  1169. X{
  1170. X    static char    rhs[MAXPAT];
  1171. X    regexp    *subpat;
  1172. X    int    c, err, line3;
  1173. X    int    apflg, pflag, gflag;
  1174. X    int    nchng;
  1175. X    char    *fptr;
  1176. X
  1177. X    pflag = FALSE;
  1178. X    Skip_White_Space;
  1179. X
  1180. X    c = *inptr++;
  1181. X    switch(c) {
  1182. X    case NL:
  1183. X        if( nlines == 0 && (Line2 = nextln(CurLn)) == 0 )
  1184. X            return(ERR);
  1185. X        setCurLn( Line2 );
  1186. X        return (1);
  1187. X
  1188. X    case '=':
  1189. X        printf("%d\n",Line2);
  1190. X        break;
  1191. X
  1192. X    case 'a':
  1193. X        if(*inptr != NL || nlines > 1)
  1194. X            return(ERR);
  1195. X
  1196. X        if(append(Line1, glob) < 0)
  1197. X            return(ERR);
  1198. X        fchanged = TRUE;
  1199. X        break;
  1200. X
  1201. X    case 'c':
  1202. X        if(*inptr != NL)
  1203. X            return(ERR);
  1204. X
  1205. X        if(deflt(CurLn, CurLn) < 0)
  1206. X            return(ERR);
  1207. X
  1208. X        if(del(Line1, Line2) < 0)
  1209. X            return(ERR);
  1210. X        if(append(CurLn, glob) < 0)
  1211. X            return(ERR);
  1212. X        fchanged = TRUE;
  1213. X        break;
  1214. X
  1215. X    case 'd':
  1216. X        if(*inptr != NL)
  1217. X            return(ERR);
  1218. X
  1219. X        if(deflt(CurLn, CurLn) < 0)
  1220. X            return(ERR);
  1221. X
  1222. X        if(del(Line1, Line2) < 0)
  1223. X            return(ERR);
  1224. X        if(nextln(CurLn) != 0)
  1225. X            nextCurLn();
  1226. X        fchanged = TRUE;
  1227. X        break;
  1228. X
  1229. X    case 'e':
  1230. X        if(nlines > 0)
  1231. X            return(ERR);
  1232. X        if(fchanged)
  1233. X            return CHANGED;
  1234. X        /*FALL THROUGH*/
  1235. X    case 'E':
  1236. X        if(nlines > 0)
  1237. X            return(ERR);
  1238. X
  1239. X        if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1240. X            return(ERR);
  1241. X
  1242. X        if((fptr = getfn()) == NULL)
  1243. X            return(ERR);
  1244. X
  1245. X        clrbuf();
  1246. X        if((err = doread(0, fptr)) < 0)
  1247. X            return(err);
  1248. X
  1249. X        strcpy(fname, fptr);
  1250. X        fchanged = FALSE;
  1251. X        break;
  1252. X
  1253. X    case 'f':
  1254. X        if(nlines > 0)
  1255. X            return(ERR);
  1256. X
  1257. X        if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1258. X            return(ERR);
  1259. X
  1260. X        if((fptr = getfn()) == NULL)
  1261. X            return(ERR);
  1262. X
  1263. X        if (nofname)
  1264. X            printf("%s\n", fname);
  1265. X        else
  1266. X            strcpy(fname, fptr);
  1267. X        break;
  1268. X
  1269. X    case 'i':
  1270. X        if(*inptr != NL || nlines > 1)
  1271. X            return(ERR);
  1272. X
  1273. X        if(append(prevln(Line1), glob) < 0)
  1274. X            return(ERR);
  1275. X        fchanged = TRUE;
  1276. X        break;
  1277. X
  1278. X    case 'j':
  1279. X        if (*inptr != NL || deflt(CurLn, CurLn+1)<0)
  1280. X            return(ERR);
  1281. X
  1282. X        if (join(Line1, Line2) < 0)
  1283. X            return(ERR);
  1284. X        break;
  1285. X
  1286. X    case 'k':
  1287. X        Skip_White_Space;
  1288. X
  1289. X        if (*inptr < 'a' || *inptr > 'z')
  1290. X            return ERR;
  1291. X        c= *inptr++;
  1292. X
  1293. X        if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1294. X            return(ERR);
  1295. X
  1296. X        mark[c-'a'] = Line1;
  1297. X        break;
  1298. X
  1299. X    case 'l':
  1300. X        if(*inptr != NL)
  1301. X            return(ERR);
  1302. X        if(deflt(CurLn,CurLn) < 0)
  1303. X            return(ERR);
  1304. X        if (dolst(Line1,Line2) < 0)
  1305. X            return(ERR);
  1306. X        break;
  1307. X
  1308. X    case 'm':
  1309. X        if((line3 = getone()) < 0)
  1310. X            return(ERR);
  1311. X        if(deflt(CurLn,CurLn) < 0)
  1312. X            return(ERR);
  1313. X        if(move(line3) < 0)
  1314. X            return(ERR);
  1315. X        fchanged = TRUE;
  1316. X        break;
  1317. X
  1318. X    case 'P':
  1319. X    case 'p':
  1320. X        if(*inptr != NL)
  1321. X            return(ERR);
  1322. X        if(deflt(CurLn,CurLn) < 0)
  1323. X            return(ERR);
  1324. X        if(doprnt(Line1,Line2) < 0)
  1325. X            return(ERR);
  1326. X        break;
  1327. X
  1328. X    case 'q':
  1329. X        if(fchanged)
  1330. X            return CHANGED;
  1331. X        /*FALL THROUGH*/
  1332. X    case 'Q':
  1333. X        if(*inptr == NL && nlines == 0 && !glob)
  1334. X            return(EOF);
  1335. X        else
  1336. X            return(ERR);
  1337. X
  1338. X    case 'r':
  1339. X        if(nlines > 1)
  1340. X            return(ERR);
  1341. X
  1342. X        if(nlines == 0)            /* The original code tested */
  1343. X            Line2 = LastLn;        /*    if(nlines = 0)        */
  1344. X                        /* which looks wrong.  RAM  */
  1345. X
  1346. X        if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1347. X            return(ERR);
  1348. X
  1349. X        if((fptr = getfn()) == NULL)
  1350. X            return(ERR);
  1351. X
  1352. X        if((err = doread(Line2, fptr)) < 0)
  1353. X            return(err);
  1354. X        fchanged = TRUE;
  1355. X        break;
  1356. X
  1357. X    case 's':
  1358. X        if(*inptr == 'e')
  1359. X            return(set());
  1360. X        Skip_White_Space;
  1361. X        if((subpat = optpat()) == NULL)
  1362. X            return(ERR);
  1363. X        if((gflag = getrhs(rhs)) < 0)
  1364. X            return(ERR);
  1365. X        if(*inptr == 'p')
  1366. X            pflag++;
  1367. X        if(deflt(CurLn, CurLn) < 0)
  1368. X            return(ERR);
  1369. X        if((nchng = subst(subpat, rhs, gflag, pflag)) < 0)
  1370. X            return(ERR);
  1371. X        if(nchng)
  1372. X            fchanged = TRUE;
  1373. X        break;
  1374. X
  1375. X    case 't':
  1376. X        if((line3 = getone()) < 0)
  1377. X            return(ERR);
  1378. X        if(deflt(CurLn,CurLn) < 0)
  1379. X            return(ERR);
  1380. X        if(transfer(line3) < 0)
  1381. X            return(ERR);
  1382. X        fchanged = TRUE;
  1383. X        break;
  1384. X
  1385. X    case 'W':
  1386. X    case 'w':
  1387. X        apflg = (c=='W');
  1388. X
  1389. X        if(*inptr != ' ' && *inptr != HT && *inptr != NL)
  1390. X            return(ERR);
  1391. X
  1392. X        if((fptr = getfn()) == NULL)
  1393. X            return(ERR);
  1394. X
  1395. X        if(deflt(1, LastLn) < 0)
  1396. X            return(ERR);
  1397. X        if(dowrite(Line1, Line2, fptr, apflg) < 0)
  1398. X            return(ERR);
  1399. X        fchanged = FALSE;
  1400. X        break;
  1401. X
  1402. X    case 'x':
  1403. X        if(*inptr == NL && nlines == 0 && !glob) {
  1404. X            if((fptr = getfn()) == NULL)
  1405. X                return(ERR);
  1406. X            if(dowrite(1, LastLn, fptr, 0) >= 0)
  1407. X                return(EOF);
  1408. X        }
  1409. X        return(ERR);
  1410. X
  1411. X    case 'z':
  1412. X        if(deflt(CurLn,CurLn) < 0)
  1413. X            return(ERR);
  1414. X
  1415. X        switch(*inptr) {
  1416. X        case '-':
  1417. X            if(doprnt(Line1-21,Line1) < 0)
  1418. X                return(ERR);
  1419. X            break;
  1420. X
  1421. X        case '.':
  1422. X            if(doprnt(Line1-11,Line1+10) < 0)
  1423. X                return(ERR);
  1424. X            break;
  1425. X
  1426. X        case '+':
  1427. X        case '\n':
  1428. X            if(doprnt(Line1,Line1+21) < 0)
  1429. X                return(ERR);
  1430. X            break;
  1431. X        }
  1432. X        break;
  1433. X
  1434. X    default:
  1435. X        return(ERR);
  1436. X    }
  1437. X    return (0);
  1438. X}  /* docmd */
  1439. X
  1440. X
  1441. X/*    doglob.c    */
  1442. Xdoglob()
  1443. X{
  1444. X    int    lin, stat;
  1445. X    char    *cmd;
  1446. X    LINE    *ptr;
  1447. X
  1448. X    cmd = inptr;
  1449. X
  1450. X    for (;;) {
  1451. X        ptr = getptr(1);
  1452. X        for (lin=1; lin<=LastLn; lin++) {
  1453. X            if (ptr->l_stat & LGLOB)
  1454. X                break;
  1455. X            ptr = getnextptr(ptr);
  1456. X        }
  1457. X        if (lin > LastLn)
  1458. X            break;
  1459. X
  1460. X        ptr->l_stat &= ~LGLOB;
  1461. X        CurLn = lin; CurPtr = ptr;
  1462. X        inptr = cmd;
  1463. X        if((stat = getlst()) < 0)
  1464. X            return(stat);
  1465. X        if((stat = docmd(1)) < 0)
  1466. X            return(stat);
  1467. X    }
  1468. X    return(CurLn);
  1469. X}  /* doglob */
  1470. X
  1471. X
  1472. X/*
  1473. X *  Software signal 2 or SIGINT is caught and the result is to resume
  1474. X *  the main loop at a command prompt.
  1475. X */
  1476. X#include <setjmp.h>
  1477. Xjmp_buf    env;
  1478. X
  1479. X#ifndef __TURBOC__
  1480. Xintr()
  1481. X{
  1482. X    puts("intr()?");
  1483. X    longjmp(env, 1);
  1484. X}
  1485. X
  1486. X#else
  1487. X
  1488. Xvoid Catcher(void)
  1489. X{
  1490. X    longjmp(env, 1);
  1491. X}
  1492. X#endif    /* !__TURBOC__ */
  1493. X
  1494. X
  1495. X/*--------  main  ---------------------------------------------------------*/
  1496. X#ifndef _Cdecl
  1497. X# define _Cdecl
  1498. X#endif
  1499. X
  1500. Xvoid _Cdecl main(argc,argv)
  1501. Xint    argc;
  1502. Xchar    **argv;
  1503. X{
  1504. X    int    stat, i, doflush;
  1505. X
  1506. X    set_ed_buf();
  1507. X    doflush=isatty(1);
  1508. X
  1509. X    if (argc>1 && argv[1][0]=='-' && argv[1][1]==0) {
  1510. X        diag = 0;
  1511. X        argc--;
  1512. X        argv++;
  1513. X    }
  1514. X    if(argc > 1) {
  1515. X        for(i = 1; i < argc; i++) {
  1516. X            if(doread(0,argv[i])==0) {
  1517. X                setCurLn( 1 );
  1518. X                strcpy(fname, argv[i]);
  1519. X                break;
  1520. X            }
  1521. X        }
  1522. X    }
  1523. X
  1524. X    for (;;) {
  1525. X
  1526. X        setjmp(env);
  1527. X        putchar(':');        /*  The command-line prompt  */
  1528. X
  1529. X#ifndef __TURBOC__
  1530. X        signal(2, intr);
  1531. X#else    /* __TURBOC__ */
  1532. X        signal(SIGINT, Catcher);
  1533. X#endif    /* !__TURBOC__ */
  1534. X
  1535. X        if (doflush)
  1536. X            fflush(stdout);
  1537. X        if (fgets(inlin, sizeof(inlin),stdin) == NULL) {
  1538. X            puts("Null input.");
  1539. X            break;
  1540. X        }
  1541. X        if(*inlin == '!') {
  1542. X            for(inptr = inlin; *inptr != NL; inptr++)
  1543. X                ;
  1544. X            *inptr = EOS;
  1545. X            system(inlin+1);
  1546. X            continue;
  1547. X        }
  1548. X        inptr = inlin;
  1549. X        if(getlst() >= 0)
  1550. X            if((stat = ckglob()) != 0) {
  1551. X                if(stat >= 0 && (stat = doglob()) >= 0) {
  1552. X                    setCurLn( stat );
  1553. X                    continue;
  1554. X                }
  1555. X            } else {
  1556. X                if((stat = docmd(0)) >= 0) {
  1557. X                    if(stat == 1)
  1558. X                        doprnt(CurLn, CurLn);
  1559. X                    continue;
  1560. X                }
  1561. X            }
  1562. X        switch (stat) {
  1563. X        case EOF:
  1564. X            _cleanup(); exit(0);
  1565. X        case FATAL:
  1566. X            fputs("FATAL ERROR\n",stderr);
  1567. X            _cleanup(); exit(1);
  1568. X        case CHANGED:
  1569. X            puts("File has been changed.");
  1570. X            break;
  1571. X        case SET_FAIL:
  1572. X            puts("`set' command failed.");
  1573. X            break;
  1574. X        case SUB_FAIL:
  1575. X            puts("string substitution failed.");
  1576. X            break;
  1577. X        case MEM_FAIL:
  1578. X            puts("Out of memory: text may have been lost." );
  1579. X            break;
  1580. X        default:
  1581. X            puts("Oops?");
  1582. X            /*  Unrecognized or failed command (this  */
  1583. X            /*  is SOOOO much better than "?" :-)      */
  1584. X        }
  1585. X    }
  1586. X}  /* main */
  1587. X/*________  end of source code  ____________________________________________*/
  1588. END_OF_FILE
  1589. if test 27843 -ne `wc -c <'ed.c'`; then
  1590.     echo shar: \"'ed.c'\" unpacked with wrong size!
  1591. fi
  1592. # end of 'ed.c'
  1593. fi
  1594. if test -f 'ed.man' -a "${1}" != "-c" ; then 
  1595.   echo shar: Will not clobber existing file \"'ed.man'\"
  1596. else
  1597. echo shar: Extracting \"'ed.man'\" \(6675 characters\)
  1598. sed "s/^X//" >'ed.man' <<'END_OF_FILE'
  1599. Xed - line-oriented text editor, similar to UN*X V7 ed
  1600. X
  1601. Xsyntax:
  1602. X    ed [existing-file]
  1603. X
  1604. X    existing-file  Only an existing file can be opened.  Otherwise
  1605. X        a nameless edit buffer is opened; a name can be used with
  1606. X        the `f' or `w' commands.
  1607. X
  1608. XAs a line editor, ed operates in one of two modes: COMMAND mode, in which
  1609. Xa colon is displayed at the screen's bottom to prompt for a command; and
  1610. XINPUT mode, in which all keyboard input is added to the file (edit buffer).
  1611. XFrom COMMAND mode, INPUT mode is entered by either the `i' or `a' commands.
  1612. XFrom INPUT mode, the COMMAND mode is restored by entering a line consisting
  1613. Xof a single period by itself.  If such a line is desired in the file, it
  1614. Xcan be created by entering (for instance) two periods, then using the `s'
  1615. Xcommand to change these to only one period.
  1616. X
  1617. XA command consists of an optional line-range specification, a single char-
  1618. Xacter indicating the command, and for some commands an optional third
  1619. Xargument.  The line-range specification is either a single line number or
  1620. Xa first-line number and a last-line number separated by a comma.  The
  1621. Xcharacter `^' means the first line of the file; `$' means the last line
  1622. Xof the file.
  1623. X
  1624. XCommands:
  1625. X    <newline>
  1626. X    If a line is specified, make that the new current line.
  1627. X    Otherwise advance the current-line-pointer by one line.
  1628. X    =    Print the line number of the current line.
  1629. X    .    (by itself)  Print the current line.
  1630. X    -    (by itself)  Move the current-line-pointer back one, and print
  1631. X    the new current line.
  1632. X    +    (by itself)  Move the current-line-pointer forward one, and
  1633. X    print the new current line.
  1634. X    !    Execute a shell command and return.
  1635. X    a    Go into INPUT mode with a new line following the current line.
  1636. X    (INPUT mode is terminated by an input line containing only a
  1637. X    period in the first column.)
  1638. X    i    Go into INPUT mode with a new line preceding the current line.
  1639. X    (INPUT mode is terminated by an input line containing only a
  1640. X    period in the first column.)
  1641. X    c    Delete the specified lines (or the current line) and then
  1642. X    add new lines in their place.  This is equivalent to a `d'
  1643. X    command followed by an `i' command.
  1644. X    d    Delete the specified range of lines (or the current line).
  1645. X    Leave the current-line-pointer at the following line.
  1646. X    e    Clear the edit buffer and begin editing a new file.  This
  1647. X    command fails if the buffer contains changes (or new lines)
  1648. X    which have not been written out.  To discard these changes
  1649. X    and edit a new file, use `E' instead of `e'.
  1650. X    E    Clear the edit buffer and begin editing a new file, regardless
  1651. X    of any changes to the current edit buffer.
  1652. X    f    Print the filename, or set it to a new name if specified.
  1653. X    g    Perform the following command on all matching lines in range
  1654. X    j    Join the addressed lines together (or the current line to the
  1655. X    previous line).
  1656. X    k    Mark the addressed line with the specified letter.  Example:
  1657. X    `17ka' puts mark "a" on line 17.
  1658. X    l    List the addressed lines, showing all non-printing characters
  1659. X    and indicating the end-of-line.
  1660. X    m    Move the specified range of lines to follow the line number
  1661. X    given.  Example:  `5,7m3' moves lines 5 through 7 "up", to
  1662. X    follow line 3.
  1663. X  p,P    Print the specified lines.
  1664. X    q    Quit the editor.  This fails if the edit buffer contains any
  1665. X    changes.  If so, use `Q' instead.
  1666. X    Q    Quit the editor absolutely.  Any changes are discarded.
  1667. X    r    Read in a file, adding it after the current line.
  1668. X    s    Substitute text on the current line.  Example:  `s/alpha/beta/'
  1669. X    finds the string "alpha" and replaces it with "beta".
  1670. X    t    Transfer (copy) the specified range of lines to follow the line
  1671. X    number given.  Example:  `5,7t7' puts a copy of lines 5 through
  1672. X    7 after line 7.
  1673. X    v    Perform the following command on all non-matching lines in range
  1674. X  w,W    Write the edit buffer out.  If a filename is given, it is used
  1675. X    and becomes the current filename.  If a range of lines is
  1676. X    specified, only those lines are written.
  1677. X    x    Write the entire buffer out to its file, and terminate.    
  1678. X    z    Print 21 lines.  `-', `.', or `+' may be given, and mean
  1679. X    "start 21 lines previous, end at current line", 
  1680. X    "start 11 lines previous, end 10 lines hence", or
  1681. X    "start at current line, end 21 lines from here", respectively.
  1682. X
  1683. XThe syntax of g and v is  <addrs> g /re/ <command>
  1684. X
  1685. XBUGS and COMMENTS
  1686. X
  1687. XThere's no "u" command. Reading files is still pretty slow. IGP.
  1688. X
  1689. X[Here's an example of how to split a line:  .s/BUGS/BU\nGS/   
  1690. XThe backslash n (\n) ends the current line after the U and starts another
  1691. Xline beginning with G.  -Ed L]
  1692. X
  1693. XThe code started out as many small files.  It is now one file, but the
  1694. Xresult isn't as clean as it could be.  I've cleaned it up some, but in
  1695. Xconverting it to TurboC compliancy I've probably lost generic C compliancy.
  1696. XHeaders describing its distribution history are appended to the code.
  1697. X
  1698. X[The i variable in function doprnt() has been eliminated and replaced by
  1699. Xthe global variable CurLn.  MSDOS signal code has been added to intercept 
  1700. XCTRL C and CTRL [BREAK] so that the program does not abort your work when 
  1701. Xyou press either of these key sequences.  -Ed L]
  1702. X
  1703. XAUTHORS
  1704. X
  1705. XBrian Beattie seems to be the original author.  Kees Bot is associated
  1706. Xwith it.  Andy Tanenbaum ported it to MINIX, and posted it to Usenet.
  1707. XBob Montante ported it to MSDOS and did some minor dressing-up.
  1708. XSomebody called Ed L added some comments above.
  1709. X
  1710. XThis version is derived from the one posted in comp.binaries.ibm.pc in ?early
  1711. X1988.
  1712. XIan Phillipps replaced the regexp stuff with Henry Spencer's version, and
  1713. Xdid some other speed-ups and tinkerings. See below.
  1714. XLewis Carroll wrote Alice's Adventures in Wonderland;
  1715. XJames Joyce wrote Finnegans Wake; they are clearly the spiritual wellsprings.
  1716. X[I think Dennis Ritchie deserves a mention here, too. IGP]
  1717. X
  1718. X[The ed.c source contains an untoggled switch for displaying line
  1719. Xnumbers and another for stripping high bits off characters.  If you
  1720. Xtype "se" at the ":" prompt, you will get a decimal version number.
  1721. X-Ed L]
  1722. X
  1723. XChanges by IGP since the last comp.binaries.ibm.pc posting:
  1724. X
  1725. XRegular expression code replaced with Henry Spencer's (lightly hacked).
  1726. XUnneccessary text copying eliminated, and the remaining quadratic-time
  1727. Xalgorithms to track line numbers removed. The program now remembers a pointer
  1728. Xto the current line.
  1729. XAll this has speeded up "g" by a factor of 20-50, so now I've documented it :-).
  1730. XLogic fixed in egets to eliminate redundant tests.
  1731. XA bug in <multiline> s/.../\n/ has been fixed.
  1732. XAll out-of-memory errors should now be reported (many were ignored before).
  1733. XA Turbo-C dependency ("cdecl") has been #ifdefed.
  1734. XAll routines now have prototypes.
  1735. XIan Phillipps (probably contactable via ex-igp@camcon.co.uk,
  1736. Xbut don't bank on it)
  1737. END_OF_FILE
  1738. if test 6675 -ne `wc -c <'ed.man'`; then
  1739.     echo shar: \"'ed.man'\" unpacked with wrong size!
  1740. fi
  1741. # end of 'ed.man'
  1742. fi
  1743. if test -f 'read.me' -a "${1}" != "-c" ; then 
  1744.   echo shar: Will not clobber existing file \"'read.me'\"
  1745. else
  1746. echo shar: Extracting \"'read.me'\" \(3023 characters\)
  1747. sed "s/^X//" >'read.me' <<'END_OF_FILE'
  1748. XHere is a version of the unix "ed" editor.
  1749. XFor its history, please see the manual page.
  1750. X
  1751. XThis source uses a very slightly hacked version of Henry Spencer's
  1752. XRegexp package. The only difference from Henry's original is that regsub
  1753. Xnow returns a value, so it should be compatible with other uses of this
  1754. Xpackage.
  1755. X
  1756. XI'm sure that Henry's package is in an archive server somewhere, but I
  1757. Xjust mailed him (for his address, look in /usr/spool/news/.... :-)
  1758. Xand was sent them by return. Don't you all do the same, though!
  1759. X
  1760. XHere are the diffs from Henry's original:
  1761. X
  1762. X*** regexp.h.orig    Fri Sep 29 11:23:29 1989
  1763. X--- regexp.h    Wed Nov 22 12:31:41 1989
  1764. X***************
  1765. X*** 15,21 ****
  1766. X      char program[1];    /* Unwarranted chumminess with compiler. */
  1767. X  } regexp;
  1768. X  
  1769. X  extern regexp *regcomp();
  1770. X  extern int regexec();
  1771. X! extern void regsub();
  1772. X  extern void regerror();
  1773. X--- 15,29 ----
  1774. X      char program[1];    /* Unwarranted chumminess with compiler. */
  1775. X  } regexp;
  1776. X  
  1777. X+ #ifdef __STDC__
  1778. X+ extern regexp *regcomp( char * );
  1779. X+ extern int regexec( regexp*, char* );
  1780. X+ extern char *regsub( regexp*, char*, char* );
  1781. X+ extern void regerror( char* );
  1782. X+ #else
  1783. X  extern regexp *regcomp();
  1784. X  extern int regexec();
  1785. X! extern char *regsub();
  1786. X  extern void regerror();
  1787. X+ #endif
  1788. X*** regsub.c.orig    Fri Sep 29 11:23:33 1989
  1789. X--- regsub.c    Wed Nov 22 12:18:52 1989
  1790. X***************
  1791. X*** 18,23 ****
  1792. X--- 18,27 ----
  1793. X   *
  1794. X   *    3. Altered versions must be plainly marked as such, and must not
  1795. X   *        be misrepresented as being the original software.
  1796. X+  *
  1797. X+  * This version modified by Ian Phillipps to return pointer to terminating
  1798. X+  * NUL on substitution string. [ Temp mail address ex-igp@camcon.co.uk ]
  1799. X+  *
  1800. X   */
  1801. X  #include <stdio.h>
  1802. X  #include <regexp.h>
  1803. X***************
  1804. X*** 32,38 ****
  1805. X  /*
  1806. X   - regsub - perform substitutions after a regexp match
  1807. X   */
  1808. X! void
  1809. X  regsub(prog, source, dest)
  1810. X  regexp *prog;
  1811. X  char *source;
  1812. X--- 36,43 ----
  1813. X  /*
  1814. X   - regsub - perform substitutions after a regexp match
  1815. X   */
  1816. X! char *
  1817. X  regsub(prog, source, dest)
  1818. X  regexp *prog;
  1819. X  char *source;
  1820. X***************
  1821. X*** 47,57 ****
  1822. X  
  1823. X      if (prog == NULL || source == NULL || dest == NULL) {
  1824. X          regerror("NULL parm to regsub");
  1825. X!         return;
  1826. X      }
  1827. X      if (UCHARAT(prog->program) != MAGIC) {
  1828. X          regerror("damaged regexp fed to regsub");
  1829. X!         return;
  1830. X      }
  1831. X  
  1832. X      src = source;
  1833. X--- 52,62 ----
  1834. X  
  1835. X      if (prog == NULL || source == NULL || dest == NULL) {
  1836. X          regerror("NULL parm to regsub");
  1837. X!         return NULL;
  1838. X      }
  1839. X      if (UCHARAT(prog->program) != MAGIC) {
  1840. X          regerror("damaged regexp fed to regsub");
  1841. X!         return NULL;
  1842. X      }
  1843. X  
  1844. X      src = source;
  1845. X***************
  1846. X*** 74,82 ****
  1847. X              dst += len;
  1848. X              if (len != 0 && *(dst-1) == '\0') {    /* strncpy hit NUL. */
  1849. X                  regerror("damaged match string");
  1850. X!                 return;
  1851. X              }
  1852. X          }
  1853. X      }
  1854. X!     *dst++ = '\0';
  1855. X  }
  1856. X--- 79,89 ----
  1857. X              dst += len;
  1858. X              if (len != 0 && *(dst-1) == '\0') {    /* strncpy hit NUL. */
  1859. X                  regerror("damaged match string");
  1860. X!                 return NULL;
  1861. X              }
  1862. X          }
  1863. X      }
  1864. X!     *dst = '\0';
  1865. X!     return dst;
  1866. X  }
  1867. X*************** end of diffs *****************
  1868. END_OF_FILE
  1869. if test 3023 -ne `wc -c <'read.me'`; then
  1870.     echo shar: \"'read.me'\" unpacked with wrong size!
  1871. fi
  1872. # end of 'read.me'
  1873. fi
  1874. echo shar: End of shell archive.
  1875. exit 0
  1876.